using System.Collections.Generic;
using System.IO;
using System.Text;

namespace Engine.FileFormats3D.C11Syndikat.QADFile
{
    internal class CollisionBlock
    {
        #region Private Fields

        private List<CollisionData> collisionData;

        #endregion Private Fields

        #region Public Constructors

        public CollisionBlock()
        {
            this.collisionData = new List<CollisionData>();
        }

        #endregion Public Constructors

        #region Public Properties

        public List<CollisionData> Data
        {
            get { return collisionData; }
            set { collisionData = value; }
        }

        public int SizeInBytes
        {
            get
            {
                int size = 2; //this includes the 00 at the end
                for (int i = 0; i < this.collisionData.Count; i++)
                {
                    size += this.collisionData[i].SizeInBytes;
                }
                return size;
            }
        }

        #endregion Public Properties

        #region Public Methods

        public override string ToString()
        {
            StringBuilder sb = new StringBuilder();
            sb.Append("entries: " + this.collisionData.Count.ToString() + " Block: ");
            for (int i = 0; i < this.collisionData.Count; i++)
            {
                sb.Append(" " + collisionData[i].BlockID.ToString());
            }
            return sb.ToString();
        }

        #endregion Public Methods

        #region Internal Methods

        internal static CollisionBlock[] FromStream(System.IO.BinaryReader br, uint collisionLength, PointerTable pointerTable)
        {
            List<CollisionBlock> collisionsBlocks = new List<CollisionBlock>();
            for (int i = 0; i < pointerTable.OffsetsCompletePosition.Count; i++)
            {
                CollisionBlock block = new CollisionBlock();
                short length = 0;
                do
                {
                    length = br.ReadInt16();
                    if (length > 0)
                    {
                        CollisionData data = CollisionBlock.CollisionData.FromStream(br, length);
                        block.collisionData.Add(data);
                    }
                } while (length > 0);
                collisionsBlocks.Add(block);
            }
            return collisionsBlocks.ToArray();
        }

        internal void AddData(ushort BlockId, ushort polygonId)
        {
            for (int i = 0; i < this.collisionData.Count; i++)
            {
                if (this.collisionData[i].BlockID == BlockId)
                {
                    this.collisionData[i].Polygons.Add(polygonId);
                    return;
                }
            }
            CollisionData newCollisionData = new CollisionData(BlockId);
            newCollisionData.Polygons.Add(polygonId);
            this.collisionData.Add(newCollisionData);
        }

        internal void Save(System.IO.BinaryWriter bw)
        {
            for (int i = 0; i < this.collisionData.Count; i++)
            {
                this.collisionData[i].Save(bw);
            }
            //Terminater byte;
            bw.Write((ushort)0);
        }

        #endregion Internal Methods

        #region Public Structs

        public struct CollisionData
        {
            #region Private Fields

            /// <summary>
            /// This is the Scenario Block, from where the Polygons are used from.
            /// </summary>
            private ushort blockID;

            /// <summary>
            /// This is a List of polygon indices which are used in the coredpending Block.
            /// </summary>
            private List<ushort> polygons;

            #endregion Private Fields

            #region Public Constructors

            public CollisionData(ushort blockId)
            {
                this.blockID = blockId;
                this.polygons = new List<ushort>();
            }

            #endregion Public Constructors

            #region Public Properties

            public ushort BlockID
            {
                get { return blockID; }
                set { blockID = value; }
            }

            public List<ushort> Polygons
            {
                get { return polygons; }
                set { polygons = value; }
            }

            public int SizeInBytes
            {
                get
                {
                    return 4 + this.polygons.Count * 2;
                }
            }

            #endregion Public Properties

            #region Public Methods

            public static CollisionData FromStream(BinaryReader br, short length)
            {
                CollisionData data = new CollisionData();
                data.polygons = new List<ushort>();

                data.blockID = (ushort)br.ReadUInt16();
                for (int i = 0; i < (int)length; i++)
                {
                    data.polygons.Add(br.ReadUInt16());
                }

                return data;
            }

            #endregion Public Methods

            #region Internal Methods

            internal void Save(BinaryWriter bw)
            {
                bw.Write((ushort)this.polygons.Count);
                bw.Write(this.blockID);
                for (int i = 0; i < this.polygons.Count; i++)
                {
                    bw.Write(this.polygons[i]);
                }
            }

            #endregion Internal Methods
        }

        #endregion Public Structs
    }
}